﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using offline2048;
using MotionFramework.Utility;
using UnityEngine;

namespace GTA
{
    public class Utils
    {
        static readonly string EncryptKey = "card";

        /// <summary>
        /// 获取分平台 配置文件 路径
        /// </summary>
        /// <returns></returns>
        public static string GetPlatformConfigPath()
        {
            #if UNITY_ANDROID
                return "android";
            #elif UNITY_IOS
                return "ios";
            #endif
            return "";
        }
        
        /// <summary>
        /// 获取设备长宽比
        /// </summary>
        /// <returns></returns>
        public static float GetScreenRatio()
        {
            return Screen.height / Screen.width;
        }

        public static string GetTextByID(string id, object args1 = null, object args2 = null, object args3 = null)
        {
            string content = ConfigManager.Instance.GetTextByID(id);
            
            if (!content.Equals(""))
            {
                return string.Format(content, args1, args2, args3).Replace("\\n", "\n");
            }
            else
            {
                return id;
            }
        }
        
        /// <summary>
        /// 获取规范化的路径
        /// </summary>
        public static string GetRegularPath(string path)
        {
            return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式
        }
        
        /// <summary>
        /// 获取当前时间戳
        /// </summary>
        /// <returns></returns>
        public static long GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long ret = Convert.ToInt64(ts.TotalMilliseconds);
            return ret;
        }
        
        /// <summary>
        /// DateTime 转时间戳
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static long DateToTimeStamp(DateTime dt)
        {
            TimeSpan ts = dt - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long ret = Convert.ToInt64(ts.TotalMilliseconds);
            return ret;
        }

        /// <summary>
        /// 时间戳 转 时间格式 DHMS
        /// </summary>
        /// <param name="ticks">单位毫秒</param>
        /// <returns></returns>
        public static string TimeStampToDHMSLimit(double ticks)
        {
            if (ticks <= 0)
            {
                ticks = 0;
            }
            var seconds = ticks / 1000;
            // var day = Math.Floor((double)(seconds / 3600 / 24));
            // var hour = Math.Floor((double)(seconds / 3600 % 24));
            var hour = Math.Floor((double)(seconds / 3600));
            var minutes = Math.Floor((double)(seconds / 60 % 60));
            var second = Math.Floor((double)(seconds % 60));
            return string.Format("{0:D2}", (int)hour) + ":" + string.Format("{0:D2}", (int)minutes) + ":" + string.Format("{0:D2}", (int)second);
        }

        /// <summary>
        /// 时间戳 转 时间格式 DHMS
        /// </summary>
        /// <param name="ticks">单位毫秒</param>
        /// <returns></returns>
        public static string TimeStampToDHMS(long ticks)
        {
            if (ticks <= 0)
            {
                ticks = 0;
            }
            var seconds = ticks / 1000;
            // var day = Math.Floor((double)(seconds / 3600 / 24));
            // var hour = Math.Floor((double)(seconds / 3600 % 24));
            var hour = Math.Floor((double)(seconds / 3600));
            var minutes = Math.Floor((double)(seconds / 60 % 60));
            var second = Math.Floor((double)(seconds % 60));
            if (hour < 72)
            {
                return string.Format("{0:D2}", (int)hour) + ":" + string.Format("{0:D2}", (int)minutes) + ":" + string.Format("{0:D2}", (int)second);
            }
            else
            {
                int days = (int)(hour / 24) + 1;
                return string.Format("{0} days left", days);
            }
        }

        /// <summary>
        /// 时间戳 转 时间格式 MS
        /// </summary>
        /// <param name="ticks">单位毫秒</param>
        /// <returns></returns>
        public static string TimeStampToMS(long ticks)
        {
            if (ticks <= 0)
            {
                ticks = 0;
            }
            var seconds = ticks / 1000;
            // var day = Math.Floor((double)(seconds / 3600 / 24));
            // var hour = Math.Floor((double)(seconds / 3600 % 24));
            var hour = Math.Floor((double)(seconds / 3600));
            var minutes = Math.Floor((double)(seconds / 60 % 60));
            var second = Math.Floor((double)(seconds % 60));
            return string.Format("{0:D2}", (int)minutes) + ":" + string.Format("{0:D2}", (int)second);
        }

        /// <summary>
        /// 时间戳 转 时间格式 DHMS
        /// </summary>
        /// <param name="ticks">单位毫秒</param>
        /// <returns></returns>
        public static string TimeStampToDHMSBy24(long ticks)
        {
            if (ticks <= 0)
            {
                ticks = 0;
            }
            var seconds = ticks / 1000;
            // var day = Math.Floor((double)(seconds / 3600 / 24));
            // var hour = Math.Floor((double)(seconds / 3600 % 24));
            var hour = Math.Floor((double)(seconds / 3600));
            var minutes = Math.Floor((double)(seconds / 60 % 60));
            var second = Math.Floor((double)(seconds % 60));
            if (hour < 24)
            {
                return string.Format("{0:D2}", (int)hour) + ":" + string.Format("{0:D2}", (int)minutes) + ":" + string.Format("{0:D2}", (int)second);
            }
            else
            {
                int days = (int)(hour / 24) + 1;
                return string.Format("{0} days left", days);
            }
        }

        /// <summary>
        /// 获取时间间隔
        /// </summary>
        /// <param name="targetData"></param>
        /// <returns></returns>
        public static TimeSpan GetDiffDate(long targetData)
        {
            DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            DateTime dt2 = dt.AddMilliseconds(targetData);
            System.TimeSpan ts1 = new System.TimeSpan(dt2.Ticks);
            System.TimeSpan ts2 = new System.TimeSpan(System.DateTime.Now.Ticks);
            System.TimeSpan subTime = ts2.Subtract(ts1).Duration();
            return subTime;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dt1"></param>
        /// <param name="dt2"></param>
        /// <returns></returns>
        public static TimeSpan GetDiffDate(DateTime dt1, DateTime dt2)
        {
            System.TimeSpan ts1 = new System.TimeSpan(dt1.Ticks);
            System.TimeSpan ts2 = new System.TimeSpan(dt2.Ticks);
            System.TimeSpan subTime = ts2.Subtract(ts1).Duration();
            return subTime;
        }

        /// <summary>
        /// 时间戳转成时间格式
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        public static DateTime TimeStampToDate(long timeStamp = 0)
        {
            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            if (timeStamp == 0)
                timeStamp = GetTimeStamp();
            DateTime dt = startTime.AddMilliseconds(timeStamp);
            return dt;
        }

        /// <summary>
        /// UTC时间戳转成时间格式
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        public static DateTime TimeStampToDateUTC(long timeStamp = 0)
        {
            DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            if (timeStamp == 0)
                timeStamp = GetTimeStamp();
            DateTime dt = startTime.AddMilliseconds(timeStamp);
            return dt;
        }

        /// <summary>
        /// 获取UTC时间
        /// </summary>
        /// <returns></returns>
        public static string GetUTCTime()
        {
            return DateTime.UtcNow.ToString();
        }

        
        /// <summary> 
        /// 判断两个日期是否在同一周 
        /// </summary> 
        /// <param name="tick1">开始日期</param> 
        /// <param name="tick2">结束日期</param>
        /// <returns></returns> 
        public static bool IsInSameWeek(long tick1, long tick2)
        {
            DateTime startDt1 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            DateTime dtmS = startDt1.AddMilliseconds(tick1);
            DateTime startDt2 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            DateTime dtmE = startDt2.AddMilliseconds(tick2);

            TimeSpan ts = dtmE - dtmS;
            double dbl = ts.TotalDays;
            int intDow = Convert.ToInt32(dtmE.DayOfWeek);
            if (intDow == 0) intDow = 7;
            if (dbl >= 7 || dbl >= intDow)
                return false;
            else
                return true;
        }


        /// <summary>
        /// 目标时间跟当前是否同一天
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        public static bool IsSameDay(long timeStamp)
        {
            long nowTime = GetTimeStamp();
            long zeroTime = nowTime - ((nowTime + 8 * 3600000) % 86400000);
            if (timeStamp > nowTime)
            {
                if (zeroTime - timeStamp < 24 * 60 * 60)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (timeStamp < nowTime)
            {
                if (zeroTime - timeStamp < 24 * 60 * 60)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;
            }
        }

        /// <summary>
		/// 目标时间跟当前是否同一天(网络时间)
		/// </summary>
		/// <param name="timeStamp"></param>
		/// <param name="nowTime">取自网络时间</param>
		/// <returns></returns>
        public static bool IsSameDayByNetTime(long timeStamp, long nowTime)
        {
            long zeroTime = nowTime - ((nowTime + 8 * 3600000) % 86400000);

            if (timeStamp > nowTime)
            {
                if (timeStamp - zeroTime  < 24 * 60 * 60)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (timeStamp < nowTime)
            {
                if (timeStamp >= zeroTime)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 时间字符串转时间戳
        /// </summary>
        /// <param name="dataString"></param>
        /// <returns></returns>
        public static DateTime ParseDateTime(string dataString)
        {
            DateTime dt = DateTime.Parse(dataString);
            return dt;
        }


        #region Parse

        #region Dictionary Parse To String
        /// <summary>
        /// Dictionary Parse To String
        /// </summary>
        /// <param name="parameters">Dictionary</param>
        /// <returns>String</returns>
        static public string ParseToString(IDictionary<string, object> parameters)
        {
            if (parameters == null) return "";
            if (parameters.Keys.Count <= 0) return "";
            IDictionary<string, object> sortedParams = new SortedDictionary<string, object>(parameters);
            IEnumerator<KeyValuePair<string, object>> dem = sortedParams.GetEnumerator();

            StringBuilder query = new StringBuilder("");
            while (dem.MoveNext())
            {
                string key = dem.Current.Key;
                string value = dem.Current.Value == null ? "" : dem.Current.Value.ToString();
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
                {
                    query.Append(key).Append("=").Append(value).Append("&");
                }
            }
            string content = query.ToString().Substring(0, query.Length - 1);

            return content;
        }
        #endregion

        #region String Parse To Dictionary
        /// <summary>
        /// String Parse To Dictionary
        /// </summary>
        /// <param name="parameter">String</param>
        /// <returns>Dictionary</returns>
        static public Dictionary<string, object> ParseToDictionary(string parameter)
        {
            try
            {
                String[] dataArry = parameter.Split('&');
                Dictionary<string, object> dataDic = new Dictionary<string, object>();
                for (int i = 0; i <= dataArry.Length - 1; i++)
                {
                    String dataParm = dataArry[i];
                    int dIndex = dataParm.IndexOf("=");
                    if (dIndex != -1)
                    {
                        String key = dataParm.Substring(0, dIndex);
                        String value = dataParm.Substring(dIndex + 1, dataParm.Length - dIndex - 1);
                        dataDic.Add(key, value);
                    }
                }

                return dataDic;
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #endregion

        /// <summary>
        /// Dictionary 合并
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        static public Dictionary<string, object> MergeDictionary(Dictionary<string, object> first, Dictionary<string, object> second)
        {
            if (first == null) first = new Dictionary<string, object>();
            if (second == null) return first;

            foreach (var item in second)
            {
                if (!first.ContainsKey(item.Key))
                    first.Add(item.Key, item.Value);
            }

            return first;
        }

        /// <summary>
        /// TODO ios 未实现
        /// 获取广告ID
        /// </summary>
        /// <returns></returns>
        public static string GetAdvertisingID()
        {
            string _strAdvertisingID = "none";
            if (string.IsNullOrEmpty(_strAdvertisingID))
            {
                _strAdvertisingID = "none";
#if (UNITY_ANDROID && !UNITY_EDITOR) || ANDROID_CODE_VIEW
            try
            {
                using (AndroidJavaClass up =  new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                {
                    using (AndroidJavaObject currentActivity = up.GetStatic<AndroidJavaObject>("currentActivity"))
                    {
                        using (AndroidJavaClass client =  new AndroidJavaClass("com.google.android.gms.ads.identifier.AdvertisingIdClient"))
                        {
                            using (AndroidJavaObject adInfo = client.CallStatic<AndroidJavaObject>("getAdvertisingIdInfo", currentActivity))
                            {
                                if (adInfo != null)
                                {
                                    _strAdvertisingID = adInfo.Call<string>("getId");
                                    if (string.IsNullOrEmpty(_strAdvertisingID))
                                        _strAdvertisingID = "none";
                                }
                            }
                        }
                    }
                }
            }
            catch (System.Exception e)
            {

            }
#endif
            }
            return _strAdvertisingID;
        }

        /// <summary>
        /// 判断设备是否是平板
        /// </summary>
        /// <returns></returns>
        public static bool IsPadDevice()
        {
            bool bIsTablet = false;
#if UNITY_IPHONE
            string deviceModel = SystemInfo.deviceModel.ToLower().Trim();
            if (deviceModel.StartsWith("ipad"))
            {
                bIsTablet = true;
            }
            else
            {
                bIsTablet = false;
            }
#elif UNITY_ANDROID
                        float physicScreenSize = Mathf.Sqrt(Screen.width * Screen.width + Screen.height * Screen.height) / Screen.dpi;
                        if (physicScreenSize >= 7f) //If the screen size is >= 7 inches, it's a tablet
                        {
                            bIsTablet = true;
                        }
                        else
                        {
                            bIsTablet = false;
                        }
#else
                        bIsTablet = false;
#endif
            return bIsTablet;
        }

        /// <summary>
        /// 数组随机打乱
        /// </summary>
        /// <param name="array"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T[] RandomSort<T>(T[] array)
        {
            int len = array.Length;
            List<int> list = new List<int>();
            T[] ret = new T[len];
            int i = 0;
            while (list.Count < len)
            {
                int iter = UnityEngine.Random.Range(0, len);
                if (!list.Contains(iter))
                {
                    list.Add(iter);
                    ret[i] = array[iter];
                    i++;
                }
            }
            return ret;
        }

        /// <summary>
        /// 随机排列数组元素
        /// </summary>
        /// <param name="myList"></param>
        /// <returns></returns>
        public static List<T> ListRandom<T>(List<T> list)
        {
            int index   = 0;
            int len     = list.Count;
            T temp;
            for (int i = 0; i < list.Count; i++)
            {

                index = UnityEngine.Random.Range(0, len);
                if (index != i)
                {
                    temp = list[i];
                    list[i] = list[index];
                    list[index] = temp;
                }
            }
            return list;
        }

        /// <summary>
        /// 合并list
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listA"></param>
        /// <param name="listB"></param>
        /// <returns></returns>
        public static List<T> MergeList<T>(List<T> listA, List<T> listB)
        {
            List<T> list = new List<T>();

            foreach(T o in listA)
            {
                list.Add(o);
            }

            foreach (T o in listB)
            {
                list.Add(o);
            }
            return list;
        }


        /// <summary>
        /// 保存文件
        /// </summary>
        /// <param name="data"></param>
        /// <param name="fileName"></param>
        public static void SaveFile(string data, string fileName, bool isEncrypt = false) {
            if (isEncrypt) {
                data =  Utils.Encrypt(data, EncryptKey);
            }
            // System.IO.File.WriteAllText(GenerateFilePath(fileName), data);
            FileUtility.CreateFile(GenerateFilePath(fileName), data);
        }

        /// <summary>
        /// 读取文件内容
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string ReadFile(string fileName, bool isEncrypt = false) {
            // string data = System.IO.File.ReadAllText(GenerateFilePath(fileName));
            string data = FileUtility.ReadFile(GenerateFilePath(fileName));
            if (isEncrypt) {
                data =  Utils.Decrypt(data, EncryptKey);
            }
            return data;
        }
        
        /// <summary>
        /// 生成文件保存路径
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static string GenerateFilePath(string fileName) {
            string path = "";
            #if UNITY_EDITOR
                string projectPath = Path.GetDirectoryName(Application.dataPath);
                projectPath = Utils.GetRegularPath(projectPath);
                path = string.Format("{0}/Savebox/{1}.bytes", projectPath, fileName);
            #else
                path = Application.persistentDataPath + "/" + fileName;
            #endif
            return path;
        }


        #region 加密字符串 
        /// <summary> /// 加密字符串  
        /// </summary> 
        /// <param name="str">要加密的字符串</param> 
        /// <returns>加密后的字符串</returns> 
        public static string Encrypt(string str, string encryptKey)
        {
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();   //实例化加/解密类对象  

            byte[] key = Encoding.Unicode.GetBytes(encryptKey); //定义字节数组，用来存储密钥   

            byte[] data = Encoding.Unicode.GetBytes(str);//定义字节数组，用来存储要加密的字符串 

            MemoryStream MStream = new MemoryStream(); //实例化内存流对象     

            //使用内存流实例化加密流对象  
            CryptoStream CStream = new CryptoStream(MStream, descsp.CreateEncryptor(key, key), CryptoStreamMode.Write);

            CStream.Write(data, 0, data.Length);  //向加密流中写入数据     

            CStream.FlushFinalBlock();              //释放加密流     

            return Convert.ToBase64String(MStream.ToArray());//返回加密后的字符串 
        }
        #endregion

        #region 解密字符串  
        /// <summary> 
        /// 解密字符串  
        /// </summary> 
        /// <param name="str">要解密的字符串</param> 
        /// <returns>解密后的字符串</returns>   
        public static string Decrypt(string str, string encryptKey)
        {
            DESCryptoServiceProvider descsp = new DESCryptoServiceProvider();   //实例化加/解密类对象   

            byte[] key = Encoding.Unicode.GetBytes(encryptKey); //定义字节数组，用来存储密钥   

            byte[] data = Convert.FromBase64String(str);//定义字节数组，用来存储要解密的字符串 

            MemoryStream MStream = new MemoryStream(); //实例化内存流对象     

            //使用内存流实例化解密流对象      
            CryptoStream CStream = new CryptoStream(MStream, descsp.CreateDecryptor(key, key), CryptoStreamMode.Write);

            CStream.Write(data, 0, data.Length);      //向解密流中写入数据    

            CStream.FlushFinalBlock();               //释放解密流     

            return Encoding.Unicode.GetString(MStream.ToArray());       //返回解密后的字符串 
        }
        #endregion


        /// <summary>
        /// Hashtable 方法
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static bool IsRepeat(int[] array)
        {
            Hashtable ht = new Hashtable();
            for (int i = 0; i < array.Length; i++)
            {
                if (ht.Contains(array[i]))
                {
                    return true;
                }
                else
                {
                    ht.Add(array[i], array[i]);
                }
            }
            return false;
		}
    }
}